package com.zhuangjie.redis.helper;

import com.alibaba.fastjson.JSONObject;
import com.zhaungjie.base.utils.json.JsonUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * redis增强操作助手
 *
 * @author zhuangjie
 * @date 2023/10/30
 */
@Component
public class RedisEnhanceOperationHelper {
    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * put一个hash kv并刷新整个hash key的过期时间
     *
     * @param key
     * @param field
     * @param value
     * @param expirationTimeInSeconds
     * @return
     */
    public Boolean luaImplHashPutAndExpire(String key, String field, Object value, int expirationTimeInSeconds) {
        String luaScript =
                "redis.call('HSET', KEYS[1], ARGV[1], ARGV[2])\n"
                        + "redis.call('EXPIRE', KEYS[1], ARGV[3])\n";
        String jsonFormatValue = JsonUtils.stringify(value);
        Boolean isHasError = (Boolean) redisTemplate.execute(new DefaultRedisScript<>(luaScript, Boolean.class),
                Collections.singletonList(key), field, jsonFormatValue, expirationTimeInSeconds);
        return !isHasError;
    }

    /**
     * 获取指定hash key的所有值（Map）
     *
     * @param key
     * @return {@link Map}<{@link String},{@link Object}>
     */
    public Map<String, Object> getHashObjectAndParseJsonForValue(String key, Class<?> clazz) {
        Map<String, Object> hashObject = redisTemplate.opsForHash().entries(key);
        if (hashObject == null) return null;
        Set<Map.Entry<String, Object>> entries = hashObject.entrySet();
        for (Map.Entry<String, Object> entry : entries) {
            Object value = entry.getValue();
            if (value == null) continue;
            if(!(value instanceof String)) {
                value = JsonUtils.stringify(value);
            }
            entry.setValue(JSONObject.parseObject((String)value, clazz));
        }
        return hashObject;
    }

    /**
     * 获取指定key-fields的值（values）
     */
    public <T> List<T> getHashValues(String key, List<String> fields, Class<T> clazz) {
        List<Object> list = redisTemplate.opsForHash().multiGet(key, fields);
        if (list == null || list.isEmpty()) return new ArrayList<>();
        return list.stream().map(itemObj -> JSONObject.parseObject(JSONObject.toJSONString(itemObj), clazz)).collect(Collectors.toList());
    }

    /**
     * 获取指定key-field的值
     */
    public <T> T getHashValue(String key, String field, Class<T> clazz) {
        Object value = redisTemplate.opsForHash().get(key, field);
        if (value == null) return null;
        return JSONObject.parseObject(JSONObject.toJSONString(value), clazz);
    }


    /**
     * 尝试设置key-value
     *
     * @param key
     * @param value
     * @param timeout
     * @param timeUnit
     * @return
     */
    public Boolean trySetStringKV(String key, Object value, long timeout, TimeUnit timeUnit) {
        String luaScript =
                "if redis.call('exists', KEYS[1]) == 1 then\n" +
                        "return false\n" +
                        "else\n" +
                        "redis.call('set', KEYS[1], ARGV[1])\n" +
                        "redis.call('EXPIRE', KEYS[1], ARGV[2])\n" +
                        "return true\n" +
                        "end\n";
        return (Boolean) redisTemplate.execute(new DefaultRedisScript<>(luaScript, Boolean.class),
                Collections.singletonList(key), value, timeUnit.toSeconds(timeout));
    }
}
